package edu.xlh.travel.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import edu.xlh.travel.common.Result;
import edu.xlh.travel.dao.UserDao;
import edu.xlh.travel.pojo.Hotel;
import edu.xlh.travel.pojo.TotalScore;
import edu.xlh.travel.pojo.User;
import edu.xlh.travel.pojo.WeChatUser_phoneUser;
import edu.xlh.travel.service.TotalScoreService;
import edu.xlh.travel.service.UserService;
import edu.xlh.travel.service.WeChatUser_phoneUserService;
import edu.xlh.travel.util.IdWorker;
import edu.xlh.travel.util.PageResult;
import edu.xlh.travel.util.RedisPipelined;
import edu.xlh.travel.websocket.domin.EmpInfo;
import edu.xlh.travel.websocket.domin.Emp_friend;
import edu.xlh.travel.websocket.service.EmpInfoService;
import edu.xlh.travel.websocket.service.Emp_friendService;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.transaction.Transactional;
import java.util.*;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDao userDao;

    @Autowired
    private BCryptPasswordEncoder encoder;

    @Autowired
    private RandomStringUtils randomStringUtils;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private IdWorker idWorker;

    @Autowired
    private RedisPipelined redisPipelined;

    @Autowired
    private WeChatUser_phoneUserService weChatUser_phoneUserService;

    @Autowired
    private Emp_friendService emp_friendService;

    @Autowired
    private EmpInfoService empInfoService;

    @Autowired
    private TotalScoreService totalScoreService;


    @Override
    public Result login(Map<String, String> hashMap, String verKey, HttpSession session) {


        String login = hashMap.get("login");
        //手机号正则，判断输入是否为手机号
        String ph = "^[1][3578]\\d{9}$";
        //邮箱正则，判断输入是否为邮箱
        String email = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
        //获取从前端传过来的验证码和redis中的验证码
        String vercode = hashMap.get("vercode");
        String value = redisPipelined.getCaptcha(verKey);
        //String value = (String) redisTemplate.opsForValue().get(verKey);
        if(StringUtils.isEmpty(vercode) || StringUtils.isEmpty(value)) {
            return new Result(203,"请输入验证码或者验证码已过期刷新页面");
        }
        if (login.matches(ph)) {
            String password = hashMap.get("password");
            User user = findByMobileAndPassword(login , password);
            if(user != null ) {
                if(!vercode.equals(value)) {
                    return new Result(204,"验证码错误，请重新输入");
                }
                session.setAttribute("user",user);
                Map<String , String> map = new HashMap<>();
                map.put("username",user.getName());
                redisTemplate.opsForValue().set("webSocketSessionUserId",user.getId());
                return new Result(200,"登陆成功",map);
            }else {
                return new Result(201,"登陆失败,请检查账号密码");
            }
        } else if (login.matches(email)) {
            String password = hashMap.get("password");
            User user = findByEmailAndPassword(login , password);
            if(user != null) {
                if(!vercode.equals(value)) {
                    return new Result(204,"验证码错误，请重新输入");
                }
                session.setAttribute("user",user);
                Map<String , String> map = new HashMap<>();
                map.put("username",user.getName());
                return new Result(200,"登陆成功",map);
            }else {
                return new Result(201,"登陆失败,请检查账号密码");
            }
        } else {
            String password = hashMap.get("password");
            List<User> userList = findByName(login);
            User user = null;
            if(userList != null) {
                if(!vercode.equals(value)) {
                    return new Result(204,"验证码错误，请重新输入");
                }
                for (User user1 : userList) {
                    String encodedPassword = user1.getPassword();
                    String salt = user1.getSalt();
                    if (encoder.matches(password+salt,encodedPassword)) {
                        user = user1;
                        break;
                    }
                }
                session.setAttribute("user",user);
                Map<String , String> map = new HashMap<>();
                map.put("username",user.getName());
                return new Result(200,"登陆成功",map);
            }else {
                return new Result(201,"登陆失败,请检查账号密码");
            }
        }
    }

    private List<User> findByName(String login) {
        return userDao.findByName(login);
    }

    public User findByMobileAndPassword(String login, String password) {
        User user = userDao.findByMobile(login);
        String salt = user.getSalt();
        if(user!=null && encoder.matches(password+salt,user.getPassword())){
            return user;
        }else{
            return null;
        }
    }

    private User findByEmailAndPassword(String login, String password) {
        User user = userDao.findByEmail(login);
        if(user!=null && encoder.matches(password+user.getSalt(),user.getPassword())){
            return user;
        }else{
            return null;
        }
    }

    @Override
    public Result findByMobile(String mobile) {
        User user = userDao.findByMobile(mobile);
        String ph = "^[1][3578]\\d{9}$";
        if (mobile == null || mobile.equals("")) {
            return new Result(201 , "手机号不能为空");
        }
        if (!mobile.matches(ph)) {
            return new Result(202 , "请输入正确的手机号");
        }
        if (user != null) {
            return new Result(203,"您想要注册的手机号已经存在");
        }
        return new Result(200 , "手机号可以注册");
    }

    @Override
    public Result findByEmail(String email) {
        User user = userDao.findByEmail(email);
        String em = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
        if (email.equals("") || email == null) {
            return new Result(201 , "邮箱不能为空");
        }
        if (!email.matches(em)) {
            return new Result(202 , "请输入正确的邮箱");
        }
        if (user != null) {
            return new Result(203,"该邮箱已被注册",user);
        }
        return new Result(200 , "邮箱可以注册");
    }

    @Override
    public Result register(User user, String code) {
        if(code==null || code.equals("")){
            return new Result(201,"请输入验证码");
        }
        //从redis获取验证码
        String checkcodeRedis =(String) redisTemplate.opsForValue().get("checkcode_"+user.getMobile());
        if(checkcodeRedis==null || checkcodeRedis.equals("")){
            return new Result(202,"请获取验证码");
        }
        //对比前端传过来的验证码
        if(!checkcodeRedis.equals(code)){
            return new Result(203,"验证码错误");
        }
        if (user == null) {
            return new Result(204,"请完善注册信息");
        }
        user.setId(idWorker.nextId()+"");
        //生成盐
        String salt = UUID.randomUUID().toString();
        user.setPassword(encoder.encode(user.getPassword()+salt));
        user.setSalt(salt);
        user.setIsVip("0");
        user.setSex("0".equals(user.getSex()) ? "女" : "男");
        user.setAge(0);
        user.setPerm("0");
        User useSave = userDao.save(user);
        //注册websocket好友列表
        Emp_friend emp_friend = new Emp_friend().setId(idWorker.nextId() + "")
                .setEmpId(user.getId())
                .setFriendGroupId("1");
        emp_friendService.save(emp_friend);
        emp_friend.setId(idWorker.nextId() + "");
        emp_friend.setFriendGroupId("2");
        emp_friendService.save(emp_friend);
        EmpInfo empInfo = new EmpInfo();
        empInfo.setId(user.getId());
        empInfo.setUsername(user.getName());
        empInfo.setAvatar("http://tp2.sinaimg.cn/1833062053/180/5643591594/0");
        empInfoService.save(empInfo);
        if (useSave == null) {
            return new Result(205,"注册失败");
        }
        return new Result(200,"注册成功");
    }

    @Override
    public void sendSms(String mobile) {
        //产生随机数
        String checkcode = RandomStringUtils.randomNumeric(6);
        //向缓存发一份
        redisTemplate.opsForValue().set("checkcode_"+mobile,checkcode,1, TimeUnit.HOURS);
        //放入消息队列
        Map<String,String> map = new HashMap();
        map.put("mobile","15361158505");
        map.put("checkcode",checkcode);
        //发送给用户
        rabbitTemplate.convertAndSend("sms",map);
        //测试
        System.out.println("验证码："+checkcode);
    }

    @Override
    public void updateByPrimaryKeySelective(User user) {
        userDao.save(user);
    }

    @Override
    public Optional<User> findById(String userId) {
        return userDao.findById(userId);
    }

    @Override
    public Result findAll(int page, int limit , HttpSession session) {
        User user = (User)session.getAttribute("admin");
        if (user == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        /*Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> userList = new ArrayList<>();
                userList.add(criteriaBuilder.equal(root.get("delFlag"), "0"));
                return criteriaBuilder.and(userList.toArray(new Predicate[userList.size()]));
            }
        };*/
        Pageable pageable= PageRequest.of(page-1,limit);
        Page<User> userListPage  = userDao.findAll(pageable);
        if (userListPage!=null) {
            return new Result(0 , "用户分页数据获取成功" , new PageResult<User>(userListPage.getTotalElements(), userListPage.getContent()));
        }
        return new Result(201 , "返回用户列表失败");
    }

    @Override
    public Result edit(String id, User user , HttpSession session) {
        User userFromSession = (User)session.getAttribute("admin");
        if (userFromSession == null) {
            return new Result(205,"会话过期，请重新登陆");
        }
        if (id.equals(userFromSession.getId())) {
            return new Result(206,"无权修改自身权限");
        }
        //手机号正则，判断输入是否为手机号
        String ph = "^[1][3578]\\d{9}$";
        //邮箱正则，判断输入是否为邮箱
        String email = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";
        if (!user.getMobile().matches(ph) || !user.getEmail().matches(email)) {
            return new Result(201,"请输入正确的邮箱或手机号码");
        }
        User phoneIsExited = userDao.findByMobile(user.getMobile());
        if (phoneIsExited != null && !id.equals(phoneIsExited.getId())) {
            return new Result(202,"该手机已经被其他用户注册，编辑失败，请使用其他手机号码");
        }
        User emailIsExited = userDao.findByEmail(user.getEmail());
        if (emailIsExited != null && !id.equals(emailIsExited.getId())) {
            return new Result(203,"该邮箱已经被其他用户注册，编辑失败，请使用其他邮箱");
        }
        String isAdmin = user.getPerm();
        if (StringUtils.isEmpty(isAdmin)) {
            user.setPerm("0");
        }
        user.setId(id);
        int rows1 = userDao.updateUserByUserId(user);
        int rows2 = empInfoService.updateEmpInfoByUserId(user.getId() , user.getName());
        if (rows1 < 1 || rows2 < 1) {
           return new Result(204,"更新失败");
        }
         return new Result(200,"更新成功");
    }

    @Override
    public Integer getUserCount() {
        return Math.toIntExact(userDao.count());
    }

    @Override
    public Result getUserInfo(HttpServletRequest request) {
        JSONObject weChatUser = (JSONObject)request.getServletContext().getAttribute("weChatUser");
        HashMap<String , String> hashMap = new HashMap();
        HttpSession session = request.getSession();
        if (weChatUser != null) {
            String openId = (String) weChatUser.get("openId");
            WeChatUser_phoneUser weChatUser_phoneUser = weChatUser_phoneUserService.findByOpenId(openId);
            //微信第一次修改，无邮箱和手机号
            if (weChatUser_phoneUser == null) {
                hashMap.put("openId",(String) weChatUser.get("openid"));
                hashMap.put("name",(String) weChatUser.get("nickName"));
                hashMap.put("mobile","");
                hashMap.put("email","");
                hashMap.put("age","");
                session.setAttribute("weChatUser" , hashMap);
                return new Result(200 , "微信首次登录，请绑定手机号" , hashMap);
            } else { //微信绑定手机号以后，显示手机号为账号主体的信息，修改也偏向机号为账号主体的信息
                User user = userDao.findById(weChatUser_phoneUser.getUserId()).get();
                hashMap.put("openId",(String) weChatUser.get("openid"));
                hashMap.put("name",user.getName());
                hashMap.put("mobile",user.getMobile());
                hashMap.put("email",user.getEmail());
                hashMap.put("age",user.getAge().toString());
                session.setAttribute("weChatUser" , hashMap);
                return new Result(200  , hashMap);
            }
        }
        //手机号登录就是原来的手机号为账号主体的信息
        User user = (User) session.getAttribute("user");
        return new Result(200 , user);

    }

    @Override
    public Result change(User user, HttpSession session) {
        User userFromSession = (User)session.getAttribute("user");
        HashMap weChatUserFromSession = (HashMap)session.getAttribute("weChatUser");
        if (userFromSession == null && weChatUserFromSession == null) {
            return new Result(201);
        }
        System.out.println(weChatUserFromSession);
        boolean isFirstWeChatLogin = false;
        //微信用户的一次登录需要绑定手机号
        if (weChatUserFromSession != null) {
            WeChatUser_phoneUser weChatUser_phoneUse = weChatUser_phoneUserService
                    .findByOpenId((String)weChatUserFromSession.get("openId"));
            if (weChatUser_phoneUse == null) {
                isFirstWeChatLogin = true;
            }
        }
        HashMap hashMap = new HashMap();
        String mobile = user.getMobile();
        if (!StringUtils.isEmpty(mobile)) {
            hashMap.put("mobile" , mobile);
        }
        Integer age = user.getAge();
        if (!StringUtils.isEmpty(age)) {
            hashMap.put("age" , age);
        }
        String sex = user.getSex();
        if (!StringUtils.isEmpty(sex)) {
            hashMap.put("sex" , sex);
        }

        if (isFirstWeChatLogin)  {
            if (!hashMap.containsKey("mobile")) {
                return new Result(200 , "请绑定手机");
            }
            User byMobile = userDao.findByMobile(mobile);
            if (hashMap.containsKey("mobile") && (byMobile == null)) {
                //注册为新用户
            } else {
                WeChatUser_phoneUser weChatUser_phoneUser = new WeChatUser_phoneUser();
                String openId = (String) weChatUserFromSession.get("openId");
                weChatUser_phoneUser.setOpenId(openId);
                weChatUser_phoneUser.setUserId(byMobile.getId());
                weChatUser_phoneUser.setId(idWorker.nextId()+"");
                System.out.println(openId +"\t\t\t\t" + byMobile.toString());
                int rows1 = weChatUser_phoneUserService.save(weChatUser_phoneUser);
                session.setAttribute("user" , byMobile);
                int rows2 = userDao.updateUserByUserId(user);
            }
        } else {//手机号登录或者微信绑定手机号后就直接对用户信息修改
            if (userFromSession != null) {
                user.setId(userFromSession.getId());
            }
            if (weChatUserFromSession != null)  {
                String openId = (String) weChatUserFromSession.get("openId");
                String userId = weChatUser_phoneUserService.findByOpenId(openId).getUserId();
                user.setId(userId);
            }
            int rows = userDao.updateUserByUserId(user);
        }
        int rows2 = empInfoService.updateEmpInfoByUserId(user.getId() , user.getName());
        return new Result(200 , "信息修改成功");
    }

    @Override
    public void updateIsVipByUserId(String userId , String isVip) {
        userDao.updateIsVipByUserId(userId , isVip);
    }

    @Override
    public Result batchDelete(JSONArray jsonArray, HttpSession session) {
        List<User> userList = JSON.parseArray(jsonArray.toJSONString() , User.class);
        try {
            userDao.deleteInBatch(new Iterable<User>() {
                @Override
                public Iterator<User> iterator() {
                    return userList.iterator();
                }
            });
        }catch (Exception e) {
            return new Result(201);
        }
        return new Result(200);
    }

    @Override
    public Result wechatLogin(HttpSession session) {
        User byMobile = userDao.findByMobile("15361158505");
        session.setAttribute("user" ,byMobile );
        return new Result(200);
    }

    @Override
    public Result doVip(HttpSession session) {
        User user = (User)session.getAttribute("user");
        String id = user.getId();
        try {
            userDao.updateIsVipByUserId(id , "1");
            TotalScore totalScore = new TotalScore();
            totalScore.setId(idWorker.nextId() + "");
            totalScore.setUserId(user.getId());
            String name = user.getName();
            totalScore.setUserName(name);
            totalScore.setTotalScore("0");
            totalScore.setCreateTime(new Date());
            totalScore.setModifyTime(new Date());
            totalScoreService.save(totalScore);
        }  catch (Exception e) {
            return new Result(201 , "开通会员失败");
        }
        user.setIsVip("1");
        return new Result(200 , "开通会员成功");
    }

    @Override
    public Result QueryUserByCondition(Integer page, Integer limit, User user, HttpSession session) {
        User userFromSession = (User)session.getAttribute("admin");
        if (userFromSession == null) {
            return new Result(201,"会话过期，请重新登陆");
        }
        Specification specification = new Specification() {
            @Override
            public Predicate toPredicate(Root root, CriteriaQuery criteriaQuery, CriteriaBuilder criteriaBuilder) {
                List<Predicate> userList = new ArrayList<>();
                if (!StringUtils.isEmpty( user.getName())) {
                    userList.add(criteriaBuilder.like(root.get("name") , "%" + user.getName() + "%"));
                }
                if (!StringUtils.isEmpty( user.getMobile())) {
                    userList.add(criteriaBuilder.like(root.get("mobile") , "%" + user.getMobile() + "%"));
                }
                if (!StringUtils.isEmpty( user.getEmail())) {
                    userList.add(criteriaBuilder.like(root.get("email") , "%" + user.getEmail() + "%"));
                }
                if (!StringUtils.isEmpty( user.getSex())) {
                    userList.add(criteriaBuilder.equal(root.get("sex") , user.getSex()));
                }
                return criteriaBuilder.and(userList.toArray(new Predicate[userList.size()]));
            }
        };
        Pageable pageable= PageRequest.of(page-1,limit);
        Page<User> userListPage  = userDao.findAll(specification , pageable);
        if (userListPage!=null) {
            return new Result(0 , "用户分页数据获取成功" , new PageResult<User>(userListPage.getTotalElements(), userListPage.getContent()));
        }
        return new Result(201 , "返回用户列表失败");
    }

    @Override
    public Result checkIsVip(HttpSession session) {
        User user = (User)session.getAttribute("user");
        if (user == null) {
            return new Result(205,"会话过期，请重新登陆");
        }
        return new Result(200 , "1".equals(user.getIsVip()) ? "" :"您不是会员无法使用该支付方式");
    }

}
